"""
剪映模板扫描服务

负责扫描模板目录，提取模板信息并保存到数据库
"""

import json
import asyncio
from pathlib import Path
from typing import Dict, List, Any, Optional
from datetime import datetime
from loguru import logger

from src.core.di import Service, Inject
from src.services.jianying_template_analyzer import JianyingTemplateAnalyzer
from src.repositories.jianying_template_repository import JianyingTemplateRepository


@Service("jianying_template_scanner")
class JianyingTemplateScanner:
    """
    剪映模板扫描服务
    
    功能：
    1. 扫描指定目录下的所有模板子文件夹
    2. 提取每个模板的详细信息
    3. 将模板信息保存到数据库
    4. 支持增量扫描和更新
    """

    def __init__(self,
                 analyzer: JianyingTemplateAnalyzer = Inject(JianyingTemplateAnalyzer),
                 template_repo: JianyingTemplateRepository = Inject(JianyingTemplateRepository)):
        self.logger = logger.bind(component="JianyingTemplateScanner")
        self.analyzer = analyzer
        self.template_repo = template_repo

    def scan_templates_directory(self, templates_dir: str, force_update: bool = False) -> Dict[str, Any]:
        """
        扫描模板目录
        
        Args:
            templates_dir: 模板目录路径
            force_update: 是否强制更新已存在的模板
            
        Returns:
            扫描结果统计
        """
        templates_path = Path(templates_dir)
        
        if not templates_path.exists():
            raise FileNotFoundError(f"模板目录不存在: {templates_dir}")
        
        if not templates_path.is_dir():
            raise ValueError(f"路径不是目录: {templates_dir}")

        self.logger.info(f"开始扫描模板目录: {templates_dir}")

        # 获取所有子文件夹
        template_dirs = [d for d in templates_path.iterdir() if d.is_dir()]
        
        scan_stats = {
            "total_found": len(template_dirs),
            "processed": 0,
            "new_templates": 0,
            "updated_templates": 0,
            "failed_templates": 0,
            "skipped_templates": 0,
            "start_time": datetime.now(),
            "template_results": []
        }

        self.logger.info(f"找到 {len(template_dirs)} 个模板目录")

        # 处理每个模板
        for template_dir in template_dirs:
            try:
                result = self._process_single_template(template_dir, force_update)
                scan_stats["template_results"].append(result)
                scan_stats["processed"] += 1

                if result["action"] == "created":
                    scan_stats["new_templates"] += 1
                elif result["action"] == "updated":
                    scan_stats["updated_templates"] += 1
                elif result["action"] == "skipped":
                    scan_stats["skipped_templates"] += 1

            except Exception as e:
                self.logger.error(f"处理模板失败 {template_dir.name}: {e}")
                scan_stats["failed_templates"] += 1
                scan_stats["template_results"].append({
                    "template_id": template_dir.name,
                    "action": "failed",
                    "error": str(e)
                })

        scan_stats["end_time"] = datetime.now()
        scan_stats["duration"] = (scan_stats["end_time"] - scan_stats["start_time"]).total_seconds()

        self.logger.info(f"扫描完成: {scan_stats}")
        return scan_stats

    def _process_single_template(self, template_dir: Path, force_update: bool) -> Dict[str, Any]:
        """
        处理单个模板
        
        Args:
            template_dir: 模板目录路径
            force_update: 是否强制更新
            
        Returns:
            处理结果
        """
        template_id = template_dir.name

        # 检查模板是否已存在
        existing_template = self.template_repo.get_by_template_id(template_id)

        # 如果已存在且不强制更新，则跳过
        if existing_template and not force_update:
            return {
                "template_id": template_id,
                "action": "skipped",
                "reason": "already_exists"
            }

        # 分析模板
        try:
            analysis_result = self.analyzer.analyze_template_structure(str(template_dir))
            replacement_template = self.analyzer.extract_replacement_template(analysis_result)
        except Exception as e:
            raise ValueError(f"模板分析失败: {e}")

        # 准备数据
        template_data, segments_data = self._prepare_database_data(analysis_result, replacement_template)

        # 保存到数据库
        self.template_repo.create_or_update_template(template_data, segments_data)
        action = "updated" if existing_template else "created"

        return {
            "template_id": template_id,
            "action": action,
            "video_segments_count": len(analysis_result.get("video_segments", [])),
            "device_fields_count": len(analysis_result.get("device_info", {}))
        }

    def _prepare_database_data(self, analysis_result: Dict[str, Any], replacement_template: Dict[str, Any]) -> tuple:
        """准备数据库数据"""
        template_id = analysis_result["template_id"]

        # 提取基本信息
        device_info = analysis_result.get("device_info", {})
        video_segments = analysis_result.get("video_segments", [])
        summary = analysis_result.get("analysis_summary", {})

        # 准备模板数据
        template_data = {
            "template_id": template_id,
            "template_name": analysis_result.get("template_name", template_id),
            "template_path": analysis_result["template_path"],
            "template_description": analysis_result.get("template_description", ""),
            "duration_seconds": summary.get("total_video_duration", 0),
            "fps": analysis_result.get("fps", 30.0),
            "project_id": analysis_result.get("project_id", ""),
            "canvas_width": analysis_result.get("canvas_info", {}).get("width", 0),
            "canvas_height": analysis_result.get("canvas_info", {}).get("height", 0),
            "canvas_ratio": analysis_result.get("canvas_info", {}).get("aspect_ratio", ""),
            "tracks_count": analysis_result.get("tracks_info", {}).get("total", 0),
            "video_tracks_count": analysis_result.get("tracks_info", {}).get("video_tracks", 0),
            "audio_tracks_count": analysis_result.get("tracks_info", {}).get("audio_tracks", 0),
            "materials_count": summary.get("materials_count", 0),
            "video_segments_count": summary.get("video_segments_count", 0),
            "effects_count": sum(analysis_result.get("effects_info", {}).values()),
            "creation_time": analysis_result.get("creation_time", 0),
            "modification_time": analysis_result.get("modification_time", 0),
        }

        # 设置JSON字段
        template = type('Template', (), template_data)()
        template.set_device_info = lambda x: setattr(template, 'device_info', json.dumps(x, ensure_ascii=False))
        template.set_analysis_data = lambda x: setattr(template, 'analysis_data', json.dumps(x, ensure_ascii=False))
        template.set_replacement_template = lambda x: setattr(template, 'replacement_template', json.dumps(x, ensure_ascii=False))

        template.set_device_info(device_info)
        template.set_analysis_data(analysis_result)
        template.set_replacement_template(replacement_template)

        template_data.update({
            "device_info": template.device_info,
            "analysis_data": template.analysis_data,
            "replacement_template": template.replacement_template
        })

        # 准备视频片段数据
        segments_data = []
        for segment in video_segments:
            segment_data = {
                "segment_index": segment.get("segment_index", 0),
                "segment_id": segment.get("segment_id", ""),
                "material_id": segment.get("material_id", ""),
                "local_material_id": segment.get("local_material_id", ""),
                "material_name": segment.get("material_name", ""),
                "material_path": segment.get("path", ""),
                "target_start": segment.get("target_start", 0),
                "target_duration": segment.get("target_duration", 0),
                "target_end": segment.get("target_end", 0),
                "source_start": segment.get("source_start", 0),
                "source_duration": segment.get("source_duration", 0),
                "material_width": segment.get("material_width", 0),
                "material_height": segment.get("material_height", 0),
                "material_fps": segment.get("material_fps", 0),
                "material_has_audio": segment.get("material_has_audio", False),
                "transform_x": segment.get("transform_x", 0),
                "transform_y": segment.get("transform_y", 0),
                "transform_scale_x": segment.get("transform_scale_x", 1.0),
                "transform_scale_y": segment.get("transform_scale_y", 1.0),
                "transform_rotation": segment.get("transform_rotation", 0),
                "effects_count": segment.get("effects_count", 0),
                "effects_data": json.dumps(segment.get("effects", []), ensure_ascii=False)
            }
            segments_data.append(segment_data)

        return template_data, segments_data

    def get_template_by_id(self, template_id: str) -> Optional[Dict[str, Any]]:
        """根据ID获取模板信息"""
        template = self.template_repo.get_with_segments(template_id)

        if not template:
            return None

        return template.to_dict(include_relationships=True)

    def search_templates(self,
                        duration_min: Optional[float] = None,
                        duration_max: Optional[float] = None,
                        canvas_ratio: Optional[str] = None,
                        min_segments: Optional[int] = None,
                        max_segments: Optional[int] = None) -> List[Dict[str, Any]]:
        """搜索模板"""
        templates = self.template_repo.search_templates(
            duration_min=duration_min,
            duration_max=duration_max,
            canvas_ratio=canvas_ratio,
            min_segments=min_segments,
            max_segments=max_segments
        )

        return [template.to_dict() for template in templates]

    def get_scan_statistics(self) -> Dict[str, Any]:
        """获取扫描统计信息"""
        return self.template_repo.get_statistics()
